home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-01-06 | 25.6 KB | 965 lines | [TEXT/MMCC] |
- //
- // CTCPStream.cp
- //
- // TurboTCP library
- // TCP stream class
- //
- // Copyright © 1993-95, FrostByte Design / Eric Scouten
- //
-
- #include "CTCPStream.h"
-
- #include "CTCPAsyncCall.h"
- #include "CTCPResolverCall.h"
-
- #if !TurboTCP_UH2
- #define TCPIOCompletionUPP TCPIOCompletionProc
- #endif
-
- #if TurboTCP_CFM
- UniversalProcPtr CTCPStream::notifyProcUPP =
- NewRoutineDescriptor((ProcPtr) CTCPStream::NotifyProc, uppTCPNotifyProcInfo, GetCurrentISA());
- #endif
-
-
- //***********************************************************
-
- CTCPStream::CTCPStream
- (CTCPEndpoint& theEndpoint, // endpoint object which is using this stream
- long recBufferSize, // size of the receive buffer we need; min 4K enforced
- short autoReceiveSize, // number of entries in RDS for auto-receive
- short autoReceiveNum) // number of auto-receive calls to issue at once
-
- // Create a new TCP stream. Allocates the receive buffer (if there’s enough memory).
-
- // The stream can be configured to automatically receive data. If auto-receive is used,
- // the stream object will automatically issue TCPNoCopyRcv calls as needed and respond to
- // completion notifications when data arrives; data will be returned by the HandleDataArrived
- // method or by the receive bypass procedure (see InstallRcvBypassProc).
-
- // If auto-receive is used, you should not send NoCopyRcv and Rcv messages to this stream.
- // They may conflict with the auto-receive calls. Auto-receive cannot be turned on or off
- // once the stream object is created.
-
- : itsEndpoint(&theEndpoint), qNotifyEntry(this), qDisposeEntry(this)
- {
-
- // clear all of our variables
-
- macTCPStream = nil;
- itsBuffer = nil;
- itsAsyncCalls.qHead = itsAsyncCalls.qTail = nil;
- hasSessionOpen = pendingOpen = pendingClose = remoteClose
- = pendingAbort = pendingNotify = pendingDispose = false;
-
- itsBufferSize = 0L;
- rcvUrgent = false;
-
- itsULPtimeout = 0;
- itsULPaction = 0;
- itsValidityFlag = 0;
- itsCommandTimeoutValue = 0;
- itsTosFlags = 0;
- itsPrecedence = 0;
- itsDontFrag = 0;
- itsTimeToLive = 0;
- itsSecurity = 0;
- itsOptionCnt = 0;
- sendNextUrgent = 0;
- sendNextPush = false;
-
- notifClosing = false;
- notifTimeout = false;
- notifTerminate = false;
- notifDataArrived = false;
- notifUrgent = false;
- notifICMP = false;
- disposeOnTerminate = false;
- receivedClose = false;
- receivedTerminate = false;
-
- if (autoReceiveSize > autoReceiveMax)
- itsAutoReceiveSize = autoReceiveMax;
- else
- itsAutoReceiveSize = autoReceiveSize;
- if (autoReceiveNum < 1)
- itsAutoReceiveNum = 1;
- else
- itsAutoReceiveNum = autoReceiveNum;
-
- qNotifyEntry.qType = notifyStream;
- qDisposeEntry.qType = disposeStream;
-
-
- // create the receive buffer
-
- if (recBufferSize < minReceiveSize) // if caller requested a buffer that is too small,
- recBufferSize = minReceiveSize; // beef it up to acceptable size (4K)
- itsBuffer = ::NewHandle(recBufferSize);
- ThrowIfNil_(itsBuffer);
- itsBufferSize = recBufferSize;
-
-
- //
- // Don’t create TCP stream here. Therefore, if a session is never opened and the program
- // crashes (or ExitToShell is used by the programmer), MacTCP will remain stable.
- //
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::Dispose()
-
- // Get rid of a TCP stream. Deallocates the receive buffer. If a session is still open,
- // issues an Abort command, then postpones its disposal so completion routines still
- // have a valid object to call.
-
- {
- TCPiopb theReleaseParam;
-
- // assume that the endpoint object is going away also
-
- itsEndpoint = nil;
-
-
- // we’re no longer in delayed disposal queue
-
- pendingDispose = false;
-
-
- // initiate a graceful close if necessary
-
- if (hasSessionOpen && !receivedClose) {
- Close();
- disposeOnTerminate = true;
- return;
- }
-
-
- // abort any connections that are yet to open
-
- if (pendingOpen) {
- Abort();
- disposeOnTerminate = true;
- return;
- }
-
-
- // if calls are still outstanding, wait a while
-
- if (itsAsyncCalls.qHead) {
- if ((macTCPStream) && pendingOpen) { // get rid of the thing…
- Abort();
- PostponeDispose();
- return;
- }
- if ((macTCPStream) && pendingOpen) {
- DoSyncCall(TCPRelease, &theReleaseParam); // perhaps this will shake it loose
- macTCPStream = nil; // 2.0b5 bug fix: remember that we killed the stream
- }
- PostponeDispose();
- return;
- }
-
-
- // if connection is still there, release stream to see if that shakes things loose
-
- if (macTCPStream && hasSessionOpen && !receivedTerminate) {
- DoSyncCall(TCPRelease, &theReleaseParam);
- macTCPStream = nil;
- PostponeDispose();
- return;
- }
-
-
- // make sure that terminate notice has been received
-
- if (hasSessionOpen && !receivedTerminate) {
- PostponeDispose();
- return;
- }
-
-
- // release the stream from MacTCP
-
- if (macTCPStream)
- DoSyncCall(TCPRelease, &theReleaseParam);
- CTCPDriver::gTCPDriver->RemoveActiveStream(this);
-
-
- // release the receive buffer
-
- ::DisposeHandle(itsBuffer);
- macTCPStream = nil;
- itsBufferSize = 0L;
-
- delete this;
- }
-
-
- // -- basic user TCP calls --
-
- //***********************************************************
-
- void CTCPStream::OpenConnection
- (Boolean passive, // true for passive open; false for active open
- ip_addr theRemoteIP, // IP address of remote host (0 matches any host on listen)
- b_16 theRemotePort, // TCP port of remote host (0 matches any port on listen)
- b_16 theLocalPort) // TCP port of local machine (0 for randomly-assigned port)
-
- // Opens a TCP session (either passive or active). Note that MacTCP seems to fail when
- // non-zero values are used for theRemoteIP and theRemotePort.
-
- {
- TCPiopb theCreateParam;
- TCPiopb theOpenParam;
- OSErr theResult;
-
-
- // ensure that MacTCP is awake & ready for us
-
- if (!(CTCPDriver::gTCPDriver->CheckTCPDriver()))
- ThrowOSErr_(noTCPError);
-
-
- // if the stream hasn’t been created yet, create one now
-
- if (!macTCPStream) {
- ::MoveHHi(itsBuffer); // lock the receive buffer
- ::HLock(itsBuffer);
-
- theCreateParam.csParam.create.rcvBuff = *itsBuffer;
- theCreateParam.csParam.create.rcvBuffLen = itsBufferSize;
- #if TurboTCP_CFM
- theCreateParam.csParam.create.notifyProc = (TCPNotifyUPP) notifyProcUPP;
- #else
- theCreateParam.csParam.create.notifyProc = &NotifyProc;
- #endif
- theCreateParam.csParam.create.userDataPtr = (Ptr) this;
-
- macTCPStream = (Ptr) 1; // preempt the check for no stream present
- theResult = DoSyncCall(TCPCreate, &theCreateParam);
-
- if (theResult == noErr) { // did we get a valid stream?
- CTCPDriver::gTCPDriver->RegisterActiveStream(this); // yes, register in global stream list
- macTCPStream = (Ptr) theCreateParam.tcpStream;
- } else {
- macTCPStream = nil;
- HandleOpenFailed(theResult);
- }
- }
-
-
- // don’t allow open if already opening
-
- if (!(hasSessionOpen || pendingOpen)) {
-
- // fill in parms to open call
-
- theOpenParam.csParam.open.ulpTimeoutValue = itsULPtimeout;
- theOpenParam.csParam.open.ulpTimeoutAction = itsULPaction;
- theOpenParam.csParam.open.validityFlags = itsValidityFlag;
- theOpenParam.csParam.open.commandTimeoutValue = itsCommandTimeoutValue;
- theOpenParam.csParam.open.remoteHost = theRemoteIP;
- theOpenParam.csParam.open.remotePort = theRemotePort;
- theOpenParam.csParam.open.localPort = theLocalPort;
- theOpenParam.csParam.open.tosFlags = itsTosFlags;
- theOpenParam.csParam.open.precedence = itsPrecedence;
- theOpenParam.csParam.open.dontFrag = itsDontFrag;
- theOpenParam.csParam.open.timeToLive = itsTimeToLive;
- theOpenParam.csParam.open.security = itsSecurity;
- theOpenParam.csParam.open.optionCnt = itsOptionCnt;
- ::BlockMoveData(&itsOptions, &theOpenParam.csParam.open.options, 40);
- theOpenParam.csParam.open.userDataPtr = (Ptr) this;
- pendingOpen = true;
- receivedClose = receivedTerminate = false;
-
- // perform the call
-
- theResult = DoAsyncCall((passive ? TCPPassiveOpen : TCPActiveOpen), &theOpenParam);
- if (theResult)
- HandleOpenFailed(theResult);
-
- // pull IP address/port info from remote host
-
- itsRemoteIP = theOpenParam.csParam.open.remoteHost;
- itsRemotePort = theOpenParam.csParam.open.remotePort;
- itsLocalIP = theOpenParam.csParam.open.localHost;
- itsLocalPort = theOpenParam.csParam.open.localPort;
- }
- else
- HandleOpenFailed(connectionExists);
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::Close()
-
- // Signal that the connection should be closed. The stream’s owner should wait until it
- // receives the tcpStreamClosed message before disposing of the stream object.
- // This will allow time for the host to close gracefully.
-
- {
- TCPiopb theCloseParam;
- OSErr theResult;
-
- if ((hasSessionOpen && (!pendingAbort) && (!pendingClose)) || remoteClose) {
- pendingClose = true;
- pendingOpen = remoteClose = false;
- theCloseParam.csParam.close.ulpTimeoutValue = itsULPtimeout;
- theCloseParam.csParam.close.ulpTimeoutAction = itsULPaction;
- theCloseParam.csParam.close.validityFlags = itsValidityFlag;
- theCloseParam.csParam.close.userDataPtr = (Ptr) this;
- theResult = DoAsyncCall(TCPClose, &theCloseParam);
- if ((theResult != noErr) && (theResult != connectionDoesntExist))
- HandleTCPError(theResult, TCPClose);
- }
- }
-
-
- //***********************************************************
-
- void CTCPStream::Abort()
-
- // Cancel the connection immediately. This call is performed synchronously. USE THIS CALL
- // WITH CAUTION! MacTCP seems to get quite confused when a session is closed and
- // data hasn’t all been received.
-
- {
- TCPiopb theAbortParam;
- OSErr theResult;
-
- if ((hasSessionOpen || pendingOpen) && (!pendingAbort)) {
- pendingAbort = true;
- pendingOpen = pendingClose = remoteClose = false;
- theAbortParam.csParam.abort.userDataPtr = (Ptr) this;
- theResult = DoSyncCall(TCPAbort, &theAbortParam);
- if (theResult)
- HandleTCPError(theResult, TCPAbort);
- else
- receivedClose = true;
- }
- }
-
-
- //***********************************************************
-
- void CTCPStream::NoCopyRcv
- (rdsEntry* itsRDS, // receive data structure (see TCP dev guide, p30)
- b_16 itsRDSSize, // number of entries in RDS
- b_16 itsTimeOut) // command timeout value in seconds (0 = infinite)
-
- // Receive data without copying from TCP’s internal buffers. The completion routine in
- // CTCPAsyncCall will take care of returning the RDS automatically. IF YOU ARE USING
- // AUTO-RECEIVE, DO NOT CALL THIS METHOD!
-
- {
- TCPiopb theRcvParam;
- OSErr theResult;
-
- theRcvParam.csParam.receive.commandTimeoutValue = itsTimeOut;
- theRcvParam.csParam.receive.rdsPtr = (Ptr) itsRDS;
- theRcvParam.csParam.receive.rdsLength = itsRDSSize;
- if (itsRDSSize > autoReceiveMax)
- theRcvParam.csParam.receive.rdsLength = autoReceiveMax;
- theRcvParam.csParam.receive.userDataPtr = (Ptr) this;
- theRcvParam.csParam.open.options[36] = (Byte) itsAutoReceiveSize;
-
- theResult = DoAsyncCall(TCPNoCopyRcv, &theRcvParam);
- if ((theResult != noErr) && (theResult != connectionClosing))
- HandleTCPError(theResult, TCPNoCopyRcv);
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::BfrReturn
- (Ptr itsRDS) // the RDS structure to return
-
- // Return a receive buffer to MacTCP used by the NoCopyRcv method. You should never need
- // to call this method, since it is done automatically by the CTCPAsyncCall::Dispatch()
- // method which handles all asynchronous completions.
-
- {
- TCPiopb theRcvParam;
-
-
- // reject attempt to return buffers after the session is closed…
- // MacTCP has done it already (I think)
-
- if (hasSessionOpen) {
- theRcvParam.csParam.receive.rdsPtr = itsRDS;
- theRcvParam.csParam.receive.userDataPtr = (Ptr) this;
-
- DoSyncCall(TCPRcvBfrReturn, &theRcvParam);
- // ignore errors — this is bad practice, but…
- }
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::Send
- (wdsEntry* itsWDS, // write data structure (see TCP dev guide, p30)
- b_16 itsTimeOut, // command timeout value in seconds (0 = infinite)
- Boolean disposeWDS, // dispose of WDS and data structure when completed
- Boolean notifyWhenDone) // notify endpoint object when send operation completes
- // (notification via HandleDataSent or HandleSendFailed)
-
- // Send data on the TCP stream using the Write Data Structure (WDS) structure. The
- // asynchronous completion routine can optionally dispose (DisposPtr) of the WDS and its
- // associated data structures once the write operation is completed. If so, the buffers you
- // provide must be expendable.
-
- {
- TCPiopb theSendParam;
- OSErr theResult;
-
-
- // ensure that at least one byte is being sent
-
-
- if ((*itsWDS).length == 0)
- return;
-
-
- // fill in parms to send call
-
- theSendParam.csParam.send.ulpTimeoutValue = itsTimeOut;
- theSendParam.csParam.send.ulpTimeoutAction = itsULPaction;
- theSendParam.csParam.send.validityFlags = itsValidityFlag;
- theSendParam.csParam.send.pushFlag = sendNextPush;
- theSendParam.csParam.send.urgentFlag = sendNextUrgent;
- theSendParam.csParam.send.wdsPtr = (Ptr) itsWDS;
- theSendParam.csParam.send.userDataPtr = (Ptr) this;
-
- theSendParam.csParam.open.timeToLive = notifyWhenDone;
- theSendParam.csParam.open.security = disposeWDS;
- // ^^^^ this isn’t pretty, but it’s efficient
-
- sendNextPush = false;
- sendNextUrgent = 0;
-
-
- // perform the call
-
- theResult = DoAsyncCall(TCPSend, &theSendParam);
- if (theResult)
- HandleTCPError(theResult, TCPSend);
- }
-
-
- //***********************************************************
-
- void CTCPStream::Receive
- (Ptr theData, // receive buffer
- b_16 itsDataSize, // size of receive buffer in bytes
- b_16 itsTimeOut) // command timeout (in seconds, 0 = infinite)
-
- // Receive data and copy to a user buffer. Should not be used if auto-receive
- // is active.
-
- {
- TCPiopb theRcvParam;
- OSErr theResult;
-
- theRcvParam.csParam.receive.commandTimeoutValue = itsTimeOut;
- theRcvParam.csParam.receive.rcvBuff = theData;
- theRcvParam.csParam.receive.rcvBuffLen = (unsigned short) itsDataSize;
- theRcvParam.csParam.receive.userDataPtr = (Ptr) this;
-
- theResult = DoAsyncCall(TCPRcv, &theRcvParam);
- if (theResult)
- HandleTCPError(theResult, TCPRcv);
- }
-
-
- //***********************************************************
-
- void CTCPStream::Status
- (TCPStatusPB* theStatusBlock) // user buffer for TCP status info
-
- // Returns a large pile of information about the TCP connection.
-
- {
- TCPiopb theStatusParam;
- short i;
- Ptr p;
- OSErr result;
-
- result = DoSyncCall(TCPStatus, &theStatusParam);
- ::BlockMoveData(&theStatusParam.csParam, theStatusBlock, 66);
- if ((result) || (theStatusParam.ioResult != noErr)) {
- i = 0;
- p = (Ptr) theStatusBlock;
- while (i++<66)
- *(p++) = 0;
- }
- }
-
-
- //***********************************************************
-
- b_16 CTCPStream::ConnectionState()
-
- // Returns the current status of the MacTCP stream. For definitions of the state codes,
- // see TCP reference manual, p56.
-
- {
- TCPStatusPB theStatusBlock;
-
- Status(&theStatusBlock);
- return theStatusBlock.connectionState;
- }
-
-
- // -- specialized functions for sending data --
-
- //***********************************************************
-
- void CTCPStream::SendBfrCpy
- (const void* theData, // the bytes to read
- unsigned short theDataSize) // number of bytes to read
-
- // Send a range of bytes to the TCP stream. Prepares a WDS for the Send method and copies
- // the bytes from the caller’s buffer to a data buffer which can persist beyond the procedure
- // or object which generated the data.
-
- {
- wdsEntry* itsWDS = nil;
- Ptr itsNewBuffer = nil;
-
-
- // make sure there’s something to send
-
- if (theDataSize == 0)
- return;
-
- Try_ {
-
- // create the two buffers
-
- itsWDS = (wdsEntry*) ::NewPtr(8); // WDS with room for one entry
- itsNewBuffer = ::NewPtr(theDataSize);
-
-
- // copy stuff to new buffer
-
- ::BlockMoveData(theData, itsNewBuffer, theDataSize);
- (*itsWDS).length = theDataSize;
- (*itsWDS).ptr = itsNewBuffer;
- (*(++itsWDS)).length = 0;
- --itsWDS;
-
-
- // send data, using default timeout value
-
- Send(itsWDS, itsULPtimeout, true, false);
- // TurboTCP 2.0 NOTE: completion of Send
- // is no longer called
- }
-
- Catch_(err) {
- ::DisposePtr((Ptr) itsWDS);
- ::DisposePtr(itsNewBuffer);
- ThrowSame_;
- }
- EndCatch_;
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::SendBfrNoCpy
- (const void* theData, // the bytes to send
- unsigned short theDataSize, // number of bytes to send
- Boolean disposeWhenDone, // true to dispose of the buffer (via DisposePtr)
- // when completed (use only if this pointer was
- // allocated as a pointer, not a handle deref)
- Boolean notifyWhenDone) // true to notify the endpoint object when completed
- // (via HandleDataSent or HandleSendFailed)
-
- // Send a range of bytes to the TCP stream. Prepares a WDS for the Send method. Does not
- // copy the bytes.
-
- {
- wdsEntry *itsWDS = nil;
-
-
- // make sure there’s something to send
-
- if (theDataSize == 0)
- return;
-
- Try_ {
-
- // create the WDS buffer & fill it in
-
- itsWDS = (wdsEntry*) ::NewPtr(8); // WDS with room for one entry
-
- (*itsWDS).length = theDataSize;
- (*itsWDS).ptr = (Ptr) theData;
- (*(++itsWDS)).length = 0;
- --itsWDS;
-
-
- // send data, using default timeout value
-
- Send(itsWDS, itsULPtimeout, disposeWhenDone, notifyWhenDone);
- }
-
- Catch_(err) {
- ::DisposePtr((Ptr) itsWDS);
- ThrowSame_;
- }
- EndCatch_;
-
- }
-
-
- // -- notification routines --
-
- //***********************************************************
-
- void CTCPStream::HandleDataSent // private method
- (wdsEntry* WDSPtr, // the WDS structure
- Boolean disposeWhenDone, // true to dispose of memory units
- Boolean notifyWhenDone) // true to notify endpoint object
-
- // Respond to successful data sending. Notifies endpoint object and disposes of data if
- // requested. Disposes of WDS structure.
-
- {
- wdsEntry* theDisposePtr = WDSPtr;
- while ((*theDisposePtr).length) {
- if ((notifyWhenDone) && (itsEndpoint))
- itsEndpoint->HandleDataSent((*theDisposePtr).ptr, (*theDisposePtr).length);
- if (disposeWhenDone)
- ::DisposePtr((*theDisposePtr).ptr);
- theDisposePtr++;
- }
- ::DisposePtr((Ptr) WDSPtr);
- }
-
-
- //***********************************************************
-
- void CTCPStream::HandleSendFailed // private method
- (wdsEntry* WDSPtr, // the WDS structure
- Boolean disposeWhenDone, // true to dispose of memory chunks
- Boolean notifyWhenDone, // true to notify endpoint object
- OSErr theResultCode) // the reason for failure
-
- // Respond to failure to send data. Notifies endpoint object and disposes of data if requested.
- // Disposes of WDS structure.
-
- {
- // send error notification (once only)
-
- if (itsEndpoint)
- itsEndpoint->HandleTCPError(theResultCode, TCPSend);
- else
- disposeWhenDone = true;
-
-
- // notify and dispose each data packet in WDS
-
- wdsEntry* theDisposePtr = WDSPtr;
- while ((*theDisposePtr).length) {
- if ((notifyWhenDone) && (itsEndpoint))
- itsEndpoint->HandleSendFailed((*theDisposePtr).ptr, (*theDisposePtr).length, theResultCode);
- if (disposeWhenDone)
- ::DisposePtr((*theDisposePtr).ptr);
- theDisposePtr++;
- }
- ::DisposePtr((Ptr) WDSPtr);
-
- }
-
-
- // -- private methods for initiating TCP calls --
-
- //***********************************************************
-
- OSErr CTCPStream::DoAsyncCall // private method
- (b_16 theCsCode, // TCP operation code
- TCPiopb* theParamBlockPtr) // parameter block for TCP call
-
- // Creates a CTCPAsyncCall object and uses it to execute a TCP Device Manager call
- // asynchronously. Does not wait for completion. Fails if not enough memory to
- // create call object.
-
- // Returns result code (+1 is not returned).
-
- {
- OSErr theResult;
- CTCPAsyncCall* theCall;
-
-
- // make sure a stream was opened
-
- if (macTCPStream)
- (*theParamBlockPtr).tcpStream = (StreamPtr) macTCPStream;
- else
- return invalidStreamPtr;
-
-
- // create call object
-
- theCall = new CTCPAsyncCall(*this);
- theResult = theCall->DoAsyncCall(theCsCode, theParamBlockPtr);
- if (theResult == inProgress)
- ::Enqueue((QElemPtr) &theCall->itsStreamEntry, &itsAsyncCalls);
- return (theResult == inProgress) ? noErr : theResult;
-
- }
-
-
- //***********************************************************
-
- OSErr CTCPStream::DoSyncCall // private method
- (b_16 theCsCode, // TCP operation code
- TCPiopb* theParamBlockPtr) // parameter block for TCP call
-
- // Fills in the standard parameters for a TCP Device Manager call and executes the call.
- // Waits for completion of the call.
-
- // Returns result code (+1 is not returned).
-
- {
-
- // make sure a stream was opened
-
- if (macTCPStream)
- (*theParamBlockPtr).tcpStream = (StreamPtr) macTCPStream;
- else
- return invalidStreamPtr;
-
-
- // perform the call
-
- (*theParamBlockPtr).ioCompletion = (TCPIOCompletionUPP) nil;
- (*theParamBlockPtr).ioCRefNum = CTCPDriver::gTCPDriver->GetTCPRefNum();
- (*theParamBlockPtr).csCode = theCsCode;
- ::PBControlSync((ParmBlkPtr) theParamBlockPtr);
- return (*theParamBlockPtr).ioResult;
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::IssueAutoReceive() // private method
-
- // Issue a NoCopyRcv command to grab the next batch of data. Does nothing if auto-receive
- // is not enabled.
-
- {
- // create a new RDS with room for # of entries requested & send it to TCP
-
- Ptr newRDS;
- if (hasSessionOpen && itsAutoReceiveSize) {
- newRDS = ::NewPtr((itsAutoReceiveSize*6)+2);
- ThrowIfNil_(newRDS);
- NoCopyRcv((rdsEntry*) newRDS, itsAutoReceiveSize, 0);
- }
- }
-
-
- //***********************************************************
-
- void CTCPStream::ProcessNotify()
-
- // Respond to notifications received by the ASR during interrupt time. This routine is free
- // of interrupt-level constraints.
-
- {
- // no longer in notify queue
-
- pendingNotify = false;
-
-
- // if terminated, inform the stream owner & dispose (if appropriate)
- // clear all other notifications (they no longer apply)
-
- if (notifTerminate) {
- HandleTerminated(notifTermReason);
- hasSessionOpen = pendingOpen = pendingClose =
- remoteClose = pendingAbort = notifClosing = notifTimeout =
- notifDataArrived = notifUrgent = false;
- receivedClose = receivedTerminate = true;
- if (disposeOnTerminate)
- PostponeDispose();
- }
-
-
- // if closed, inform stream owner, wait for termination before disposing (if appropriate)
-
- if (notifClosing) {
- HandleClosing(remoteClose);
- receivedClose = true;
- notifClosing = false;
- if (disposeOnTerminate)
- PostponeDispose();
- }
-
-
- // if urgent notification, flag beginning of urgent data
-
- if (notifUrgent) {
- if (!rcvUrgent) {
- RcvUrgentBegin();
- HandleUrgentBegin();
- }
- notifUrgent = false;
- }
-
-
- // tell stream owner about other notifications, TurboTCP doesn’t respond to these
-
- if (notifTimeout) {
- HandleTimeout();
- notifTimeout = false;
- }
-
- if (notifDataArrived) {
- HandleUnexpectedData();
- notifDataArrived = false;
- }
-
- if (notifICMP) {
- HandleICMP(¬ifICMPreport);
- notifICMP = false;
- }
-
- }
-
-
- //***********************************************************
-
- void CTCPStream::ProcessAsyncCompletion
- (CTCPAsyncCall* theCall) // the call which was completed
-
- // Respond to the completion of an asynchronous call. Removes the async call object from
- // the list of outstanding calls.
-
- {
- ::Dequeue((QElemPtr) &theCall->itsStreamEntry, &itsAsyncCalls);
- }
-
-
- #ifndef __MWERKS__
- //#pragma options(!profile)
- #else
- #pragma profile off
- #endif
-
-
- //************* **********************************************
-
- void CTCPStream::PostponeDispose()
-
- // Add this stream object to the delayed disposal queue.
- // *** Runs at interrupt level. ***
-
- {
- if (pendingDispose) // ignore this if we’re already in disposal queue
- return;
- pendingDispose = true;
- disposeOnTerminate = true;
- ::Enqueue((QElemPtr) &qDisposeEntry, &(CTCPDriver::gTCPDriver->asyncQueue));
- }
-
-
- //***********************************************************
-
- void CTCPStream::PostponeNotify // protected method
- (b_16 eventCode, // event code (see TCP dev guide, p37)
- b_16 terminReason, // reason for termination (if applicable)
- struct ICMPReport* icmpMsg) // ICMP report (if applicable)
-
- // The asynchronous notification routine (ASR). Receives notification of events for all TCP
- // streams. Dispatches the notification to the proper method of the CTCPStream object. This
- // routine is installed for all TCP streams created by the CTCPStream object.
-
- // This method merely logs the kind of notification and adds this stream to the list of streams
- // to be processed next time through the event loop.
-
- // *** Runs at interrupt level. ***
-
- {
-
- // reject notifications for unexpected data if auto-receiving
-
- if ((itsAutoReceiveSize > 0) && (eventCode == TCPDataArrival))
- return;
-
-
- // install this stream in asynchronous events queue
- // CTCPDriver::ProcessNetEvents will pick it up later
-
- if (!pendingNotify) {
- ::Enqueue((QElemPtr) &qNotifyEntry, &(CTCPDriver::gTCPDriver->asyncQueue));
- pendingNotify = true;
- }
-
-
- // record the event type
-
- switch (eventCode) {
- case TCPClosing:
- remoteClose = remoteClose || !pendingClose;
- notifClosing = pendingClose = true;
- break;
-
- case TCPULPTimeout:
- notifTimeout = true;
- break;
-
- case TCPTerminate:
- notifTerminate = true;
- notifTermReason = terminReason;
- break;
-
- case TCPDataArrival:
- notifDataArrived = true;
- break;
-
- case TCPUrgent:
- notifUrgent = true;
- break;
-
- case TCPICMPReceived:
- notifICMP = true;
- ::BlockMoveData(icmpMsg, ¬ifICMPreport, 24);
- break;
- }
-
- }
-
-
- //***********************************************************
-
- pascal void CTCPStream::NotifyProc // private static method
- (StreamPtr tcpStream, // the TCP stream in question
- unsigned short eventCode, // TCP event code (see TCP dev guide, p37)
- Ptr userDataPtr, // user data pointer (in this case, the "this" pointer)
- unsigned short terminReason, // reason for termination (see TCP dev guide, p37)
- struct ICMPReport* icmpMsg) // ICMP report (if applicable)
-
- // The asynchronous notification routine (ASR). This static method just decodes the
- // userDataPtr and calls PostponeNotify for the object named. This routine is the standard
- // ASR for all TCP streams created by the CTCPStream object.
-
- {
- CTCPStream* theTCPStream = (CTCPStream*) userDataPtr;
- theTCPStream->PostponeNotify(eventCode, terminReason, icmpMsg);
- }
-